/* global define */
define([
    'jquery',
    'edx-ui-toolkit/js/utils/spec-helpers/ajax-helpers',
    'js/certificates/models/certificate_invalidation',
    'js/certificates/views/certificate_invalidation_view',
    'js/certificates/collections/certificate_invalidation_collection'
],
    function($, AjaxHelpers, CertificateInvalidationModel, CertificateInvalidationView,
             CertificateInvalidationCollection) {
        'use strict';
        describe('Field validation of invalidation model.', function() {
            var certificate_invalidation = null;
            var assertValid = function(fields, isValid, expectedErrors) {
                certificate_invalidation.set(fields);
                var errors = certificate_invalidation.validate(certificate_invalidation.attributes);

                if (isValid) {
                    expect(errors).toBe(undefined);
                } else {
                    expect(errors).toEqual(expectedErrors);
                }
            };

            var EXPECTED_ERRORS = {
                user_name_or_email_required: 'Student username/email field is required and can not be empty. ' +
                'Kindly fill in username/email and then press "Invalidate Certificate" button.'
            };

            beforeEach(function() {
                certificate_invalidation = new CertificateInvalidationModel({user: 'test_user'}, {url: 'test/url/'});
                certificate_invalidation.set({
                    notes: 'Test notes'
                });
            });

            it('accepts valid email addresses', function() {
                assertValid({user: 'bob@example.com'}, true);
                assertValid({user: 'bob+smith@example.com'}, true);
                assertValid({user: 'bob+smith@example.com'}, true);
                assertValid({user: 'bob+smith@example.com'}, true);
                assertValid({user: 'bob@test.example.com'}, true);
                assertValid({user: 'bob@test-example.com'}, true);
            });

            it('displays username or email required error', function() {
                assertValid({user: ''}, false, EXPECTED_ERRORS.user_name_or_email_required);
            });
        });

        describe('Certificate invalidation collection initialization and updates.',
            function() {
                var certificate_invalidations = null,
                    certificate_invalidation_url = 'test/url/';
                var certificate_invalidations_json = [
                    {
                        id: 1,
                        user: 'test1',
                        invalidated_by: 2,
                        created: 'Thursday, October 29, 2015',
                        notes: 'test notes for test certificate invalidation'
                    },
                    {
                        id: 2,
                        user: 'test2',
                        invalidated_by: 2,
                        created: 'Thursday, October 29, 2015',
                        notes: 'test notes for test certificate invalidation'
                    }
                ];

                beforeEach(function() {
                    certificate_invalidations = new CertificateInvalidationCollection(certificate_invalidations_json, {
                        parse: true,
                        canBeEmpty: true,
                        url: certificate_invalidation_url
                    });
                });

                it('has 2 models in the collection after initialization', function() {
                    expect(certificate_invalidations.models.length).toEqual(2);
                });

                it('model is removed from collection on destroy', function() {
                    var model = certificate_invalidations.get({id: 2});
                    model.destroy();
                    expect(certificate_invalidations.models.length).toEqual(1);
                    expect(certificate_invalidations.get({id: 2})).toBe(undefined);
                });
            }
        );

        describe('Certificate invalidation success/error messages on add/remove invalidations.', function() {
            var view = null,
                certificate_invalidation_url = 'test/url/',
                user_name_field = null,
                notes_field = null,
                invalidate_button = null,
                duplicate_user = 'test2',
                new_user = 'test4@test.com',
                requests = null;

            var messages = {
                error: {
                    empty_user_name_email: 'Student username/email field is required and can not be empty. ' +
                        'Kindly fill in username/email and then press "Invalidate Certificate" button.',
                    duplicate_user: 'Certificate of ' + (duplicate_user) + ' has already been invalidated. ' +
                        'Please check your spelling and retry.',
                    server_error: 'Server Error, Please refresh the page and try again.',
                    from_server: 'Test Message from server'
                },
                success: {
                    saved: 'Certificate has been successfully invalidated for ' + new_user + '.',
                    re_validated: 'The certificate for this learner has been re-validated and ' +
                        'the system is re-running the grade for this learner.'
                }
            };

            var certificate_invalidations_json = [
                {
                    id: 1,
                    user: 'test1',
                    invalidated_by: 2,
                    created: 'Thursday, October 29, 2015',
                    notes: 'test notes for test certificate invalidation'
                },
                {
                    id: 2,
                    user: 'test2',
                    invalidated_by: 2,
                    created: 'Thursday, October 29, 2015',
                    notes: 'test notes for test certificate invalidation'
                }
            ];

            beforeEach(function() {
                setFixtures();
                var fixture = readFixtures(
                    'templates/instructor/instructor_dashboard_2/certificate-invalidation.underscore'
                );

                setFixtures(
                    "<div class='certificate-invalidation-container'>" +
                    '   <h2>Invalidate Certificates</h2> ' +
                    "   <div id='certificate-invalidation'></div>" +
                    '</div>' +
                    "<script type='text/template' id='certificate-invalidation-tpl'>" + fixture + '</script>'
                );

                var certificate_invalidations = new CertificateInvalidationCollection(certificate_invalidations_json, {
                    parse: true,
                    canBeEmpty: true,
                    url: certificate_invalidation_url,
                    generate_certificates_url: certificate_invalidation_url

                });

                view = new CertificateInvalidationView({collection: certificate_invalidations});
                view.render();

                user_name_field = $('#certificate-invalidation-user');
                notes_field = $('#certificate-invalidation-notes');
                invalidate_button = $('#invalidate-certificate');

                requests = AjaxHelpers.requests(this);
            });

            it('verifies view is initialized and rendered successfully', function() {
                expect(view).not.toBe(undefined);
                expect(view.$el.find('table tbody tr').length).toBe(2);
            });

            it('verifies view is rendered on add/remove to collection', function() {
                var user = 'test3',
                    notes = 'test3 notes',
                    model = new CertificateInvalidationModel(
                        {user: user, notes: notes}, {url: certificate_invalidation_url}
                    );

                // Add another model in collection and verify it is rendered
                view.collection.add(model);
                expect(view.$el.find('table tbody tr').length).toBe(3);

                expect(view.$el.find('table tbody tr td:contains("' + user + '")').parent().html()).
                    toMatch(notes);
                expect(view.$el.find('table tbody tr td:contains("' + user + '")').parent().html()).
                    toMatch(user);

                // Remove a model from collection
                var collection_model = view.collection.get({id: 2});
                collection_model.destroy();

                // Verify view is updated
                expect(view.$el.find('table tbody tr').length).toBe(2);
            });

            it('verifies view error message on duplicate certificate validation.', function() {
                $(user_name_field).val(duplicate_user);
                $(invalidate_button).click();

                expect($('#certificate-invalidation div.message').text()).toEqual(messages.error.duplicate_user);
            });

            it('verifies view error message on empty username/email field.', function() {
                $(user_name_field).val('');
                $(invalidate_button).click();

                expect($('#certificate-invalidation div.message').text()).toEqual(messages.error.empty_user_name_email);
            });

            it('verifies view success message on certificate invalidation.', function() {
                $(user_name_field).val(new_user);
                $(notes_field).val('test notes for user test4');
                $(invalidate_button).click();

                AjaxHelpers.respondWithJson(
                    requests,
                    {
                        id: 4,
                        user: 'test4',
                        validated_by: 5,
                        created: 'Thursday, December 29, 2015',
                        notes: 'test notes for user test4'
                    }
                );
                expect($('#certificate-invalidation div.message').text()).toEqual(messages.success.saved);
            });

            it('verifies view server error if server returns unknown response.', function() {
                $(user_name_field).val(new_user);
                $(notes_field).val('test notes for user test4');
                $(invalidate_button).click();

                // Response with empty body
                AjaxHelpers.respondWithTextError(requests, 400, '');

                expect($('#certificate-invalidation div.message').text()).toEqual(messages.error.server_error);
            });

            it('verifies certificate re-validation request and success message.', function() {
                var user = 'test1',
                    re_validate_certificate = "div.certificate-invalidation-container table tr:contains('" +
                        user + "') td .re-validate-certificate";

                $(re_validate_certificate).click();
                AjaxHelpers.respondWithJson(requests, {});

                expect($('#certificate-invalidation div.message').text()).toEqual(messages.success.re_validated);
            });

            it('verifies error message from server is displayed.', function() {
                var user = 'test1',
                    re_validate_certificate = "div.certificate-invalidation-container table tr:contains('" +
                        user + "') td .re-validate-certificate";

                $(re_validate_certificate).click();
                AjaxHelpers.respondWithError(requests, 400, {
                    success: false,
                    message: messages.error.from_server
                });

                expect($('#certificate-invalidation div.message').text()).toEqual(messages.error.from_server);
            });
        });
    }
);
